package com.javaex.book.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.function.BiFunction;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * JavaBean参数注入工具
 *
 * @author 黄星琦
 * @Date 2022年1月20日
 */
public class BeanUtils {
	
	private static final Logger logger = LoggerFactory.getLogger(BeanUtils.class);
	
	/**
	 * 将参数注入到Bean中
	 * @param <T> Bean的类型
	 * @param clazz	Bean类型的Class对象
	 * @param getValueByName 根据参数名获取参数值的方法。在调用该方法时实现，该方法接收一个String类型参数，表示属性名
	 * @return	注入数据后的Bean实例
	 */
	public static <T> T injectDataIntoBean(Class<T> clazz, BiFunction<Class<?>, String, Object> getValueByName) {
		if (clazz == null || getValueByName == null) {
			return null;
		}
		// 创建Bean实例
		T bean = null;
		try {
			bean = clazz.getDeclaredConstructor().newInstance();
			// 获取所有属性
			Field[] fields = clazz.getDeclaredFields();
			for (Field field : fields) {
				// 获取属性名和属性类型
				String fieldName = field.getName();
				Class<?> fieldType = field.getType();
				
				// 根据属性名获取属性值
				Object value = getValueByName.apply(fieldType, fieldName);
				if (value == null) {
					continue;
				}
				
				// 拼接获取属性名对应的setter方法名
				StringBuilder setterName = new StringBuilder(fieldType == boolean.class ? "is" : "set");
				setterName.append(fieldName.substring(0, 1).toUpperCase());
				setterName.append(fieldName.substring(1));
				
				// 获取setter方法
				Method setter = bean.getClass().getDeclaredMethod(setterName.toString(), fieldType);
				// 执行setter方法，为属性赋值
				setter.invoke(bean, value);
			}
		} catch (Exception e) {
			logger.error("将数据注入bean失败\n{}", LoggerUtils.format(e, "com.javaex.book"));
		}
		return bean;
	}
}
